大数据
高并发 -> 日志* -> 分析行为 ->画像 ->推荐 -> 服务*
TCP/IP 网络模型
三次握手:确认客户端和服务端的收发正常(IO 正常),可以进行连接
C -> S : 发送 sync 包给服务端,表示客户端想与服务端建立连接
S -> C:服务端接收到客户端的 sync 包,并将 sync +ack 包,发送给客户端
表示服务端接收到客户端的请求,并回复客户端可以与服务端建立连接
C -> S: 客户端接收到服务端的 ack 包,将 ack 包发送给服务端,表示客户端马上与服务端建立连接,让服务端做好准备
四次离手:TCP 是稳定的连接,对于连接断开需要经过 Client 与 Server 双方都确认后,才可关闭
- C - >S: 发送 fin 包给服务端,表示客户端想与服务端断开连接
- S -> C: 发送 ack包给客户端,表示接收到服务端的断开请求
- S -> C: 发送 fin 包给客户端,表示服务端想与客户端断开连接
- C -> S: 发送 ack 包给服务端,服务端接收到后,表示与客户端断开连接。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| TCP/IP协议 OSI 7L参考模型 GET / www.baidu.com/ 7:应用层www.baidu.com IP:80 1212 http,smtp,ssh 4:传输层控制:【三次握手>>(传输数据)>>四次分手】 tcp,udp SOCKET:IP:PORT-IP:PORT netstat -natp 3:网络层: 192.168.9.11 ip,icmp ROUTE:下一跳 route -n 2:链路层 以太网:Ethernet:MAC ARP:全F,两点通信,交换机学习 arp -a
|

注意: 三次握手和四次离手中间不可拆分,一定针对于两台特定 IP:Port - IP:Port
1 2 3 4 5 6
| netstat antp
route -n # -n 查看 IP 地址
arp -a 0.0.0.0 默认网关
|
功能分层
层与层依赖
1,能够申请到端口号
2,路由表有下一跳条目
3,ARP能请求到下一跳MAC
4,三次握手
5,传输数据
6,四次分手

下一跳
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| 整个互联网建立在下一跳的模式下 IP是逻辑上的两个端点 MAC是物理上连接的两个节点 端点间TCP传输过程中 确认机制 状态机制 不可分割 解析数据包需要成本 交换机:二层,只关心MAC地址 学习机制: 路由器:三层,只关心IP和路由表 LVS服务器:四层,只关心PORT,状态 nginx:七层,关心socket对应关系
## 负载均衡 ##
|
LVS
LVS技术要达到的目标是:通过LVS提供的负载均衡技术和Linux操作系统实现一个高性能、高可用的服务器群集,它具有良好可靠性、可扩展性和可操作性。从而以低廉的成本实现最优的服务性能。
LVS自从1998年开始,发展到现在已经是一个比较成熟的技术项目了。可以利用LVS技术实现高可伸缩的、高可用的网络服务,例如WWW服务、Cache服务、DNS服务、FTP服务、MAIL服务、视频/音频点播服务等等,有许多比较著名网站和组织都在使用LVS架设的集群系统,例如:Linux的门户网站(www.linux.com)、向RealPlayer提供音频视频服务而闻名的Real公司(www.real.com)、全球最大的开源网站(sourceforge.net)等
LVS 参考 https://superproxy.github.io/docs/lvs/index.html
硬件
1 2 3 4
| 昂贵,性能优越 F5 BIG-IP Citrix NetScaler A10
|
软件
便宜,灵活度(开源)
|
四层 |
七层 |
|
tcp 之上的第四层协议 |
LVS 只能操作IP,端口 ,在操作系统内核中。 |
|
|
nginx haproxy httpd “apache”webserver |
LVS -DR
Director 接收用户的请求,然后根据负载均衡算法选取一台 realserver,将包转发过去,最后由realserver直接回复给用户。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| DR:Director 客户端发送对VIP的请求 lvs负载到后端某一台server 后端server处理后,直接封包回送客户端 源IP地址一定是lvs上面陪的那个公网服务地址 也就后端server要配置这个ip 后端server收到的数据包是lvs没有变动过的(IP:vip) 目标ip一定是自己持有的 so:多个server,接入互联网的server持有相同的IP,是不对的 必须将后端server中的vip隐藏起来(对外隐藏)
VIP: 虚拟服务器地址 DIP: 转发的网络地址 1,和RIP通信:ARP协议,获取Real Server的RIP:MAC地址 2,转发Client的数据包到RIP上(隐藏的VIP) RIP: 后端真实主机(后端服务器)
CIP: 客户端IP地址
|

LVS 配置实验
环境
| 主机名 |
node01 |
node02 |
node03 |
| IP 类型 |
DIP |
RIP |
RIP |
| IP |
192.168.170.101 |
192.168.170.102 |
192.168.170.103 |
实验图

步骤
配置 LVS 服务器的虚拟IP 和开启 IPv4 转发
1 2
| [root@node01 ~]# ifconfig eth0:0 192.168.170.100/24 # 临时生效 echo “1” > /proc/sys/net/ipv4/ip_forward
|
修改 RP 服务器的文件
1 2 3 4
| echo 1 > /proc/sys/net/ipv4/conf/eth0/arp_ignore echo 2 > /proc/sys/net/ipv4/conf/eth0/arp_announce echo 1 > /proc/sys/net/ipv4/conf/all/arp_ignore echo 2 > /proc/sys/net/ipv4/conf/all/arp_announce
|
配置 RP 服务器的本地环回地址
1
| ifconfig lo:0 192.168.170.100 netmask 255.255.255.255
|
在 RP 服务器上安装 httpd 服务
设置 主页
1 2 3
| cd /var/www/html vi index.html 内容: from 192.168.170.102
|
启动 httpd 服务
LVS 配置
1 2 3 4 5 6 7 8 9
| yum install ipvsadm -y ipvsadm -A -t 192.168.170.100:80 -s rr ipvsadm -a -t 192.168.170.100:80 -r 192.168.170.102 -g ipvsadm -a -t 192.168.170.100:80 -r 192.168.170.103 -g
ipvsadm -ln 浏览器刷新: 访问vip ipvsadm –lnc netstat -natp
|
keepalived
集群管理中保证集群高可用的服务软件
用于做健康检查和主备切换,这里用在 LVS 服务器,使用 LVS 服务器达到高可用 HA(High Availability)
高可用 High Available
1 2 3 4
| 1、需要心跳机制探测后端RS是否提供服务。 a) 探测down,需要从lvs中删除该RS b) 探测发送从down到up,需要从lvs中再次添加RS。 2、Lvs DR,需要主备(HA)
|
实验
环境
| 主机名 |
node01 |
node02 |
node03 |
node04 |
| 类型 |
LVS(MASTER) |
RIP1 |
RIP2 |
LVS(BACKUP) |
| IP |
192.168.170.101 |
192.168.170.102 |
192.168.170.103 |
192.168.170.104 |
实验图

步骤
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99
| # node01 上LVS 服务器上关闭之前的 ipvsadm 设置 ipvsadm -C # Clear the virtual server table. ifconfig eth0:0 down
# 在 node01、node04上安装 keepalived yum install -y keepalived
# 安装完成后, 进入 cd /etc/keepalived 目录下,备份 keepalived.conf 文件 ! Configuration File for keepalived
global_defs { notification_email { acassen@firewall.loc failover@firewall.loc sysadmin@firewall.loc } notification_email_from Alexandre.Cassen@firewall.loc smtp_server 192.168.200.1 smtp_connect_timeout 30 router_id LVS_DEVEL }
vrrp_instance VI_1 { state MASTER # 主节点 interface eth0 # 操作的网卡 virtual_router_id 51 priority 100 # 优先级 advert_int 1 authentication { auth_type PASS auth_pass 1111 } virtual_ipaddress { # VIP 虚拟IP配置 192.168.170.100/24 dev eth0 label eth0:3 } }
virtual_server 192.168.170.100 80 { delay_loop 6 lb_algo rr lb_kind DR # 指定 LVS DR模式 nat_mask 255.255.255.0 persistence_timeout 0 # 同一个IP地址在50秒内lvs转发给同一个后端服务器 protocol TCP
real_server 192.168.170.102 80 { #设置真实服务器的心跳机制 RID PORT weight 1 HTTP_GET { #心跳检测的方式 url { path / # 心跳检查的地址 status_code 200 #心跳检查返回的状态 } connect_timeout 3 nb_get_retry 3 delay_before_retry 3 } } real_server 192.168.170.103 80 { weight 1 HTTP_GET { url { path / status_code 200 } connect_timeout 3 nb_get_retry 3 delay_before_retry 3 } } } # 配置完成 keepalived.conf ,将文件拷贝到 node04 上,并修改 scp ./keepalived.conf root@192.168.170.104:/`pwd`
# keepalived.conf 修改 node04 部分内容 vrrp_instance VI_1 { state BACKUP # 从节点 interface eth0 # 操作的网卡 virtual_router_id 51 priority 50 # 优先级,从节点的优先级应低于主节点的优先级 advert_int 1 authentication { auth_type PASS auth_pass 1111 } virtual_ipaddress { # VIP 虚拟IP配置 192.168.170.100/24 dev eth0 label eth0:3 } }
# ------------------------------------------------------------------- # 在 node01、node04 上启动 keepalived 服务 service keepalived start
# 在 ifconfig 命令查看 ifocnifg
# 查看路由 ipvsadm -ln
|
Nginx
Nginx (“engine x”) 是一个高性能的 HTTP 和 反向代理 服务器,也是一个 IMAP/POP3/SMTP 代理服务器。
Apache 与 Nginx 的比较
|
Apache |
Nginx |
|
一个客户端连接开辟一个进程处理 |
仅有一个进程 |
|
同步阻塞 |
异步非阻塞 |
nginx.conf
events
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
| #工作模式与连接数上限 events { #参考事件模型,use [ kqueue | rtsig | epoll | /dev/poll | select | poll ]; epoll模型是Linux 2.6以上版本内核中的高性能网络I/O模型,如果跑在FreeBSD上面,就用kqueue模型。 use epoll; #单个进程最大连接数(最大连接数=连接数*进程数) worker_connections 65535; }
event下的一些配置及其意义 #单个后台worker process进程的最大并发链接数 worker_connections 1024; # 并发总数是 worker_processes 和 worker_connections 的乘积 # 即 max_clients = worker_processes * worker_connections # 在设置了反向代理的情况下,max_clients = worker_processes * worker_connections / 4 为什么 # 为什么上面反向代理要除以4,应该说是一个经验值 # 根据以上条件,正常情况下的Nginx Server可以应付的最大连接数为:4 * 8000 = 32000 # worker_connections 值的设置跟物理内存大小有关 # 因为并发受IO约束,max_clients的值须小于系统可以打开的最大文件数 event下的一些配置及其意义 # 而系统可以打开的最大文件数和内存大小成正比,一般1GB内存的机器上可以打开的文件数大约是10万左右 # 我们来看看360M内存的VPS可以打开的文件句柄数是多少: # $ cat /proc/sys/fs/file-max # 输出 34336 # 32000 < 34336,即并发连接总数小于系统可以打开的文件句柄总数,这样就在操作系统可以承受的范围之内 # 所以,worker_connections 的值需根据 worker_processes 进程数目和系统可以打开的最大文件总数进行适当地进行设置 # 使得并发总数小于操作系统可以打开的最大文件数目 # 其实质也就是根据主机的物理CPU和内存进行配置 # 当然,理论上的并发总数可能会和实际有所偏差,因为主机还有其他的工作进程需要消耗系统资源。 # ulimit -SHn 65535
#定义Nginx运行的用户和用户组 user www www;
#nginx进程数,建议设置为等于CPU总核心数。 worker_processes 8;
#全局错误日志定义类型,[ debug | info | notice | warn | error | crit ] error_log /var/log/nginx/error.log info;
#进程文件 pid /var/run/nginx.pid;
#一个nginx进程打开的最多文件描述符数目,理论值应该是最多打开文件数(系统的值ulimit -n)与nginx进程数相除,但是nginx分配请求并不均匀,所以建议与ulimit -n的值保持一致。 worker_rlimit_nofile 65535;
|
httpd
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| #设定http服务器 http { include mime.types; #文件扩展名与文件类型映射表 default_type application/octet-stream; #默认文件类型 #charset utf-8; #默认编码 server_names_hash_bucket_size 128; #服务器名字的hash表大小 client_header_buffer_size 32k; #上传文件大小限制 large_client_header_buffers 4 64k; #设定请求缓 client_max_body_size 8m; #设定请求缓 sendfile on; #开启高效文件传输模式,sendfile指令指定nginx是否调用sendfile函数来输出文件,对于普通应用设为 on,如果用来进行下载等应用磁盘IO重负载应用,可设置为off,以平衡磁盘与网络I/O处理速度,降低系统的负载。注意:如果图片显示不正常把这个改成off。 autoindex on; #开启目录列表访问,合适下载服务器,默认关闭。 tcp_nopush on; #防止网络阻塞 tcp_nodelay on; #防止网络阻塞 keepalive_timeout 120; #长连接超时时间,单位是秒
|
gzip
1 2 3 4 5 6 7 8 9 10 11 12 13
| gzip的一些配置及其意义 #gzip模块设置gzip on; #开启gzip压缩输出 gzip_min_length 1k; #最小压缩文件大小 gzip_buffers 4 16k; #压缩缓冲区 gzip_http_version 1.0; #压缩版本(默认1.1,前端如果是squid2.5请使用1.0) gzip_comp_level 2; #压缩等级 gzip_types text/plain application/x-javascript text/css application/xml; #压缩类型,默认就已经包含text/html,所以下面就不用再写了,写上去也不会有问题, 但是会有一个warn。 gzip_vary on; #limit_zone crawler $binary_remote_addr 10m; #开启限制IP连接数的时候需要使用
|
虚拟主机
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| 虚拟主机一些配置及其意义 #虚拟主机的配置 server{ #监听端口 listen 80; #域名可以有多个,用空格隔开 server_name www.ha97.com ha97.com; index index.html index.htm index.jsp; root /data/www/ha97; location ~ .*\.(php|php5)?${ fastcgi_pass 127.0.0.1:9000; fastcgi_index index.jsp; include fastcgi.conf; } 通过nginx可以实现虚拟主机的配置,nginx支持三种类型的虚拟主机配置, 1、基于ip的虚拟主机, (一块主机绑定多个ip地址) 2、基于域名的虚拟主机(servername) 3、基于端口的虚拟主机(listen如果不写ip端口模式) 示例基于虚拟机ip的配置,这里需要配置多个ip server { listen 192.168.20.20:80; server_name www.linuxidc.com; root /data/www; } server { listen 192.168.20.21:80; server_name www.linuxidc.com; root /data/www; }
|
location
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
| location 映射(ngx_http_core_module) location [ = | ~ | ~* | ^~ ] uri { ... } location URI {}: 对当前路径及子路径下的所有对象都生效; location = URI {}: 注意URL最好为具体路径。 精确匹配指定的路径,不包括子路径,因此,只对当前资源生效; location ~ URI {}: location ~* URI {}: 模式匹配URI,此处的URI可使用正则表达式,~区分字符大小写,~*不区分字符大小写; location ^~ URI {}: 不使用正则表达式 优先级:= > ^~ > ~|~* > /|/dir/
/loghaha.html /logheihei.html ^/log.*html$
## location 配置规则 =前缀的指令严格匹配这个查询。如果找到,停止搜索。 所有剩下的常规字符串,最长的匹配。如果这个匹配使用^〜前缀,搜索停止。 正则表达式,在配置文件中定义的顺序。 如果第3条规则产生匹配的话,结果被使用。否则,如同从第2条规则被使用
## location配置规则 location 的执行逻辑跟 location 的编辑顺序无关。 矫正:这句话不全对,“普通 location ”的匹配规则是“最大前缀”, 因此“普通 location ”的确与 location 编辑顺序无关;
但是“正则 location ”的匹配规则是“顺序匹配,且只要匹配到第一个就停止后面的匹配”; “普通location ”与“正则 location ”之间的匹配顺序是? 先匹配普通 location ,再“考虑”匹配正则 location 。 注意这里的“考虑”是“可能”的意思,也就是说匹配完“普通 location ”后,有的时候需要继续匹配“正则 location ”,有的时候则不需要继续匹配“正则 location ”。两种情况下,不需要继续匹配正则 location : ( 1 )当普通 location 前面指定了“ ^~ ”,特别告诉 Nginx 本条普通 location 一旦匹配上,则不需要继续正则匹配; ( 2 )当普通location 恰好严格匹配上,不是最大前缀匹配,则不再继续匹配正则
loghaha.html l: logha l: ^~ loghah l: loghaha.html l: =loghaha.html l: ^logh.*html$ l: ^logha.*html$
# 总结 nginx 收到请求头:判定ip,port,hosts决定server nginx location匹配:用客户端的uri匹配location的uri 先普通 顺序无关 最大前缀 匹配规则简单 打断: ^~ 完全匹配 再正则 不完全匹配 正则特殊性:一条URI可以和多条location匹配上 有顺序的 先匹配,先应用,即时退出匹配
|
请求头
1 2 3 4
| 请求头 host:决策server负责处理 uri:决策location 反向代理:proxy_pass ip:port[uri];
|
IP 访问控制
1 2 3 4 5 6 7
| IP访问控制 location { deny IP /IP段 deny 192.168.1.109; allow 192.168.1.0/24;192.168.0.0/16;192.0.0.0/8 } 规则:按照顺序依次检测,直到匹配到第一条规则
|
Nginx 的 session 一致性问题
http协议是无状态的,即你连续访问某个网页100次和访问1次对服务器来说是没有区别对待的,因为它记不住你。那么,在一些场合,确实需要服务器记住当前用户怎么办?比如用户登录邮箱后,接下来要收邮件、写邮件,总不能每次操作都让用户输入用户名和密码吧,为了解决这个问题,session的方案就被提了出来,事实上它并不是什么新技术,而且也不能脱离http协议以及任何现有的web技术
session的常见实现形式是会话cookie(session cookie),即未设置过期时间的cookie,这个cookie的默认生命周期为浏览器会话期间,只要关闭浏览器窗口,cookie就消失了。实现机制是当用户发起一个请求的时候,服务器会检查该请求中是否包含sessionid,如果未包含,则系统会创造一个名为JSESSIONID的输出 cookie返回给浏览器(只放入内存,并不存在硬盘中),并将其以HashTable的形式写到服务器的内存里面;当已经包含sessionid是,服务端会检查找到与该session相匹配的信息,如果存在则直接使用该sessionid,若不存在则重新生成新的 session。这里需要注意的是session始终是有服务端创建的,并非浏览器自己生成的。 但是浏览器的cookie被禁止后session就需要用get方法的URL重写的机制或使用POST方法提交隐藏表单的形式来实现
Session共享
首先我们应该明白,为什么要实现共享,如果你的网站是存放在一个机器上,那么是不存在这个问题的,因为会话数据就在这台机器,但是如果你使用了负载均衡把请求分发到不同的机器呢?这个时候会话id在客户端是没有问题的,但是如果用户的两次请求到了两台不同的机器,而它的session数据可能存在其中一台机器,这个时候就会出现取不到session数据的情况,于是session的共享就成了一个问题
Session一致性解决方案
1、session复制
tomcat 本身带有复制session的功能。(不讲)
2、共享session
需要专门管理session的软件,
memcached 缓存服务,可以和tomcat整合,帮助tomcat共享管理session。
1 2 3 4 5 6 7 8 9 10 11 12 13
| 安装memcached 1、安装libevent 2、安装memcached 3、启动memcached memcached -d -m 128m -p 11211 -l 192.168.170.101 -u root -P /tmp/ -d:后台启动服务 -m:缓存大小 -p:端口 -l:IP -P:服务器启动后的系统进程ID,存储的文件 -u:服务器启动是以哪个用户名作为管理用户 如果源配置了也可以用 yum –y install memcached
|
1 2 3 4 5 6 7 8 9 10 11
| 配置session共享如下: 3、拷贝jar到tomcat的lib下,jar包见附件 4、配置tomcat,每个tomcat里面的context.xml中加入 <Manager className="de.javakaffee.web.msm.MemcachedBackupSessionManager" memcachedNodes="n1:192.168.170.101:11211" sticky="false" lockingMode="auto" sessionBackupAsync="false" requestUriIgnorePattern=".*\.(ico|png|gif|jpg|css|js)$" sessionBackupTimeout="1000" transcoderFactoryClass="de.javakaffee.web.msm.serializer.kryo.KryoTranscoderFactory" />
|
注意: tomcat 集群一定要保持时间一致性
